今天本來要說極限梯度提升數 (XGBoost),但是我發現後面的篇幅可能快不夠了,今天開始的內容會調整成,無監督式學習 → 深度學習 → 如果有時間再回來補充 One-Class SVM 跟 XGBoost。
K-Means 是一種無監督學習中的聚類演算法,旨在將資料分為 K 個群集,使同一群集內的資料點之間相似度最高,而不同群集之間相似度最低。到這邊可能會有疑問,分類跟聚類差在哪? 分類要有標籤 (監督式學習),而聚類不需要有標籤 (無監督式學習),可以想像一下原始資料,如果要訓練分類模型,你在訓練之前就會知道每筆資料要分成什麼類別,但是到了聚類,你的資料完全分不出來該筆資料要分成什麼類別,只知道我這組資料要分成幾群。
$$
J = \sum_{i=1}^K \sum_{x \in C_i} |x - \mu_i|^2
$$
優點 | 缺點 |
---|---|
計算快速、可擴展、易平行 | 需先給定 k,對初始化與尺度敏感 |
易實作、常作為分群基線 | 假設球形/大小相近群,對離群值非常敏感 |
可搭配 MiniBatchKMeans 處理大規模資料 | 對非凸形狀或重疊群表現不佳 |
# Day 16 - K-Means on Iris (library dataset, full pipeline)
import seaborn as sns
import pandas as pd
import numpy as np
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans, MiniBatchKMeans
from sklearn.metrics import silhouette_score, adjusted_rand_score
from sklearn.model_selection import ParameterGrid
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# 1) 載入資料(無需外部檔案)
iris = sns.load_dataset("iris") # columns: sepal_length, sepal_width, petal_length, petal_width, species
X = iris.drop(columns=["species"])
y_true = iris["species"] # 僅作對照評估,不參與訓練(非監督)
# 2) 工程化 Pipeline:標準化 + KMeans
def make_kmeans_pipe(k):
return Pipeline([
("scaler", StandardScaler()),
("kmeans", KMeans(
n_clusters=k,
init="k-means++",
n_init=10, # 提升穩定性
max_iter=300,
random_state=42
))
])
# 3) 用 Elbow 與 Silhouette 輔助挑 k
K_RANGE = range(2, 8) # Iris 通常 2~6 即可觀察
wcss, sils = [], []
for k in K_RANGE:
pipe = make_kmeans_pipe(k).fit(X)
labels = pipe.named_steps["kmeans"].labels_
wcss.append(pipe.named_steps["kmeans"].inertia_) # WCSS
sils.append(silhouette_score(pipe.named_steps["scaler"].transform(X), labels))
print("k vs WCSS:", list(zip(K_RANGE, [round(v,2) for v in wcss])))
print("k vs Silhouette:", list(zip(K_RANGE, [round(v,4) for v in sils])))
# 4) 以 k=3 做主實驗(Iris 有 3 個物種)
k = 3
pipe = make_kmeans_pipe(k)
pipe.fit(X)
labels = pipe.named_steps["kmeans"].labels_
# 5) 非監督情境下的評估指標
sil = silhouette_score(pipe.named_steps["scaler"].transform(X), labels)
# 若有真實標籤可作參考(僅作對照用):Adjusted Rand Index(ARI)
ari = adjusted_rand_score(y_true, labels)
print(f"Silhouette Score (k={k}): {sil:.4f}")
print(f"Adjusted Rand Index vs species (k={k}): {ari:.4f}")
# 6) 簡易視覺化(PCA 2D)
Z = PCA(n_components=2, random_state=42).fit_transform(pipe.named_steps["scaler"].transform(X))
plt.figure(figsize=(6,5))
plt.scatter(Z[:,0], Z[:,1], c=labels, s=30)
plt.title(f"K-Means (k={k}) on Iris (PCA 2D)\nSilhouette={sil:.3f}, ARI={ari:.3f}")
plt.xlabel("PC1"); plt.ylabel("PC2")
plt.tight_layout(); plt.show()
# 7) 進一步:MiniBatchKMeans(大資料時)
mbk_pipe = Pipeline([
("scaler", StandardScaler()),
("kmeans", MiniBatchKMeans(
n_clusters=k, init="k-means++", random_state=42, batch_size=64, n_init=10
))
]).fit(X)
mbk_labels = mbk_pipe.named_steps["kmeans"].labels_
mbk_sil = silhouette_score(mbk_pipe.named_steps["scaler"].transform(X), mbk_labels)
print(f"MiniBatchKMeans Silhouette (k={k}): {mbk_sil:.4f}")
# 8) 粗略參數掃描(僅示例)
grid = {"kmeans__n_clusters": [2,3,4], "kmeans__n_init": [10,20]}
best = None
for params in ParameterGrid(grid):
candidate = Pipeline([("scaler", StandardScaler()), ("kmeans", KMeans(init="k-means++", max_iter=300, random_state=42))])
candidate.set_params(**params).fit(X)
labels_c = candidate.named_steps["kmeans"].labels_
sil_c = silhouette_score(candidate.named_steps["scaler"].transform(X), labels_c)
if (best is None) or (sil_c > best[0]):
best = (sil_c, params)
print("Best by Silhouette:", round(best[0],4), best[1])
k vs WCSS: [(2, 222.36), (3, 139.82), (4, 114.09), (5, 90.93), (6, 81.54), (7, 72.63)]
k vs Silhouette: [(2, 0.5818), (3, 0.4599), (4, 0.3869), (5, 0.3459), (6, 0.3171), (7, 0.3202)]
Silhouette Score (k=3): 0.4599
Adjusted Rand Index vs species (k=3): 0.6201
MiniBatchKMeans Silhouette (k=3): 0.4557
Best by Silhouette: 0.5818 {'kmeans__n_clusters': 2, 'kmeans__n_init
K-Means 在本篇範例中清楚展現了它作為無監督式分群基線的特性: 計算效率高、實作簡單、可快速提供初步的資料結構洞察。透過 Elbow 法與 Silhouette Score 的雙重分析,我們觀察到在 Iris 資料集上,幾何結構最佳的分群數為 k=2,而符合領域知識的 k=3 則在分群品質上略顯不足,顯示資料真實分佈與理想分群假設之間的落差。這種差異提醒我們,分群結果不能僅憑數學指標決定,還需結合業務目標與領域先驗做取捨。
總結來說,K-Means 是值得在專案初期引入的分群起點模型,但應搭配多種指標與方法驗證,並在必要時替換為更契合資料幾何與業務需求的分群策略。